﻿using System;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Fluid;
using Fluid.Values;
using ZYing.LiquidThemeEngine.Objects;

namespace ZYing.LiquidThemeEngine.Filters
{
    public static class AdditionalFilters
    {
        private static Regex InterpolationTemplateRegex = new Regex("{{((\\s*)(?<id>[0-9a-zA-Z][0-9a-zA-Z-_]+)(\\s*))}}", RegexOptions.Compiled);
        private static Regex InterpolationRegex = new Regex("\\$(?<id>[0-9a-zA-Z]+)\\$", RegexOptions.Compiled);
        private static string Render(string template, FilterArguments arguments)
        {
            return InterpolationTemplateRegex.Replace(template, m =>
             {
                 var id = m.Groups["id"].Value;
                 if (arguments.HasNamed(id))
                 {
                     var value = arguments[id];
                     return value.ToStringValue();
                 }
                 return string.Empty;
             });
        }

        public static async ValueTask<FluidValue> TranslationAsync(FluidValue input, FilterArguments arguments, TemplateContext ctx)
        {
            var content = input.ToStringValue();
            var context = (LiquidThemeTemplateContext)ctx;
            var locale = await context.GetLocaleDictionaryAsync(context.CultureInfo);
            if (locale.TryGetValue(content, out var template))
            {
                var value = Render(template, arguments);
                if (content.EndsWith("_html")) return new StringValue(value, false);
                return new StringValue(value);
            }
            //TODO: 处理单复数等问题
            //https://shopify.dev/themes/architecture/locales/storefront-locale-files#pluralize-translations
            //https://unicode-org.github.io/cldr-staging/charts/latest/supplemental/language_plural_rules.html
            return new StringValue($"translation missing: {content}");
        }

        private static ConcurrentDictionary<MemberNameStrategy, IFluidTemplate> PaginationTemplateCache = new ConcurrentDictionary<MemberNameStrategy, IFluidTemplate>();
        private static IFluidTemplate CreateDefaultPaginationTemplate(TemplateContext ctx)
        {
            var context = (LiquidThemeTemplateContext)ctx;
            const string template =
                "{%- if $Paginate$.$Previous$ and $Paginate$.$Previous$.$IsLink$ -%}" +
                /**/"<span class=\"prev\">" +
                /****/"<a href=\"{{$Paginate$.$Previous$.$Url$}}\">{{ txt_previous | default: $Paginate$.$Previous$.$Title$ }}</a>" +
                /**/"</span>" +
                "{%-endif-%}" +
                "{%- for pair in $Paginate$.$Parts$ -%}" +
                /**/"{%- if pair.$IsLink$ -%}" +
                /****/"<span class=\"page\">" +
                /******/"<a href=\"{{pair.$Url$}}\">{{pair.$Title$}}</a>" +
                /****/"</span>" +
                /**/"{%- else -%}" +
                /****/"<span class=\"deco\">{{pair.$Title$}}</span>" +
                /**/"{%- endif -%}" +
                "{%- endfor -%}" +
                "{%- if $Paginate$.$Next$ and $Paginate$.$Next$.$IsLink$ -%}" +
                /**/"<span class=\"prev\">" +
                /****/"<a href=\"{{$Paginate$.$Next$.$Url$}}\">{{ txt_next | default: $Paginate$.$Next$.$Title$ }}</a>" +
                /**/"</span>" +
                "{%- endif -%}";
            var str = InterpolationRegex.Replace(template, m =>
            {
                var id = m.Groups["id"].Value;
                return context.Options.MemberAccessStrategy.MemberNameStrategy(ReflectionHelper.Get(id));
            });
            var options = context.LiquidThemeEngineOptions;
            var parser = options.Parser;
            return parser.Parse(str);
        }
        private static IFluidTemplate GetDefaultPaginationTemplate(TemplateContext context)
        {
            return PaginationTemplateCache.GetOrAdd(context.Options.MemberAccessStrategy.MemberNameStrategy, (m) => CreateDefaultPaginationTemplate(context));
        }

        public static async ValueTask<FluidValue> DefaultPaginationAsync(FluidValue input, FilterArguments arguments, TemplateContext context)
        {
            if (input.ToObjectValue() is not Paginate paginate) return StringValue.Empty;
            var nextText = arguments.HasNamed("next")
                ? arguments["next"]
                : NilValue.Instance;
            var previousText = arguments.HasNamed("previous")
                ? arguments["previous"]
                : NilValue.Instance;
            context.EnterChildScope();
            context.SetValue("paginate", paginate);
            context.SetValue("txt_next", nextText);
            context.SetValue("txt_previous", previousText);
            var fluidTemplate = GetDefaultPaginationTemplate(context);
            var html = await fluidTemplate.RenderAsync(context);
            context.ReleaseScope();
            return new StringValue(html, false);
        }
    }
}